using System.Linq;

namespace System.Collections.Generic;

public static class CollectionExtensions
{
    /// <summary>
    /// 返回 <paramref name="collection1"/> 与 <paramref name="collection2"/>
    /// 的笛卡尔积（也称为叉积），如果后者为 <see langword="null"/> 则与自身。
    /// 这意味着返回集合的每个可能配对。这可以用单个 foreach 循环替换两个嵌套的 for 循环。
    /// </summary>
    public static IEnumerable<(T Left, T Right)> CartesianProduct<T>(
        this ICollection<T> collection1,
        ICollection<T> collection2 = null) =>
        collection1.SelectMany(_ => collection2 ?? collection1, (left, right) => (left, right));

    /// <summary>
    /// 使用 <see cref="ICollection{T}.Add(T)"/> 将 <paramref name="source"/> 中的每个项追加到 <paramref name="target"/>。
    /// </summary>
    public static void AddRange<T>(this ICollection<T> target, IEnumerable<T> source)
    {
        foreach (var item in source) target.Add(item);
    }

    /// <summary>
    /// 移除 <paramref name="collection"/> 中 <paramref name="predicate"/> 返回 <see langword="true"/> 或为 <see langword="null"/> 的每个项。
    /// </summary>
    public static void RemoveAll<T>(this ICollection<T> collection, Func<T, bool> predicate = null)
    {
        var itemsToRemove = collection.Where(predicate ?? (item => true)).ToList();

        foreach (var item in itemsToRemove)
        {
            collection.Remove(item);
        }
    }

    /// <summary>
    /// 清空集合并添加 <paramref name="newValues"/> 中的值。
    /// </summary>
    public static void SetItems<T>(this ICollection<T> collection, IEnumerable<T> newValues)
    {
        // 如果两个变量指向同一个对象，则不应执行任何操作。否则这将清空集合并不添加任何内容。
        if (Equals(collection, newValues)) return;

        collection.Clear();
        collection.AddRange(newValues);
    }
}
